package biz

import (
	"encoding/json"
	"fmt"
	"t11Lib/t11Errors"
	"t11Lib/t11Log"
	"t11Lib/t11Model"
	"t11Lib/t11Util"
	"亚太-iot-服务器/biz/wxBiz/weixinOperator"
	"亚太-iot-服务器/models"
)

type devBiz struct{}

var DevBiz devBiz

//返回bool（是否redirect消息给到websocket）以及处理错误
type MqttMsgHandlerFunc func(conn *t11Model.DbConn, body *MqttMsg) t11Errors.T11Error

func (self *devBiz) HandleGatewayCmdPassThrough(body *MqttMsg) t11Errors.T11Error {

	dbConn := t11Model.NewDbConn()
	gateway, err := models.GatewayDao.GetById(dbConn, body.GatewayId)
	if err != nil {
		return err
	}

	token := models.ParseJwtToken(gateway.UserId)
	return WsMsgSender.SendMsg(token, body)
}

func (self *devBiz) HandleGatewayCmdDelDevSuccess(conn *t11Model.DbConn, body *MqttMsg) t11Errors.T11Error {

	/**
	1.管理员删除，只删除网关和门锁的绑定关系
	2.不删除用户对门锁的设置
	3.不删除门锁的分享关系
	*/
	e := t11Model.Transacrtion(conn, func() t11Errors.T11Error {

		t11Log.Debuglnf("delete device start")

		tokens, e := models.UserDeviceDao.GetTokensByDeviceId(conn, body.DevId)
		if e != nil {
			return e
		}

		for _, token := range tokens {
			//TODO:发送设备删除的消息给用户
			e = weixinOperator.TemplateMsg.SendGatewayUnbindMsg(token.UserId)
		}
		t11Log.Debuglnf("delete device end")
		return nil
	})
	return e
}

func (self *devBiz) HandleGatewayCmdDevAddCanceled(conn *t11Model.DbConn, body *MqttMsg) t11Errors.T11Error {
	_, err := GatewayBiz.GetById(conn, body.GatewayId)
	return err
}

func (self devBiz) ListGuarantees(conn *t11Model.DbConn, devs []*models.Device) ([]*models.Guarantee, t11Errors.T11Error) {

	var devIds []string

	for _, dev := range devs {
		devIds = append(devIds, dev.Id)
	}

	return models.GuranteeDao.ListByDevIds(conn, devIds)
}

func (self *devBiz) HandleGatewayCmdDevAddSuccess(conn *t11Model.DbConn, body *MqttMsg) t11Errors.T11Error {
	_, err := models.GatewayDao.GetById(conn, body.GatewayId)
	if err != nil {
		return err
	}

	// todo 向用户推送设备添加成功信息

	//添加门锁
	return t11Model.Transacrtion(conn, func() t11Errors.T11Error {
		e := models.DeviceDao.SetDeviceGateway(conn, body.DevId, body.GatewayId)
		if e != nil {
			return e
		}

		tokens, e := models.UserDeviceDao.GetTokensByDeviceId(conn, body.DevId)
		if e != nil {
			return e
		}

		openId := tokens[0].UserId
		return weixinOperator.TemplateMsg.SendLockBindSuccessMsg(openId)
	})
}


func (self devBiz) SetKv(conn *t11Model.DbConn, msg *MqttMsg, data []byte) t11Errors.T11Error {

	//设置kv
	kv := &models.DeviceKv{}
	kv.Key = fmt.Sprintf("%02X", data[1])
	kv.Value = t11Util.BytesToHexStringWithoutSpace(data[2:])
	kv.SetId(msg.DevId, kv.Key + "-" + kv.Value[2:6])

	if kv.Key == "02" {
		id := kv.Value[2:6]
		kv.Key += "_" + id
	}

	//若value为空，则删除相应的数据
	var retErr t11Errors.T11Error
	if kv.Value == "" {
		retErr = models.DeviceKvDao.Delete(t11Model.NewDbConn(), kv)
	} else {
		retErr = models.DeviceKvDao.CreateOrUpdate(t11Model.NewDbConn(), kv)
	}
	if retErr == nil {
		self.notifyWs(conn, msg)
	}
	return retErr
}

func (self devBiz) upLoadOpenLog(conn *t11Model.DbConn, msg *MqttMsg, data []byte) t11Errors.T11Error {

	keyType := ""
	_lockUserId := msg.Data[8:12]
	lockUserId, err := t11Util.HexStringToDecimal(_lockUserId)
	if err != nil {
		return err
	}

	tokens, err := models.UserDeviceDao.GetTokensByDeviceId(conn, msg.DevId)
	if err != nil {
		return err
	}

	devKv, _ := models.DeviceKvDao.GetByKey(conn, _lockUserId)

	switch msg.Data[14:16] {
	case "01":
		keyType = "密码钥匙"
		break
	case "02":
		keyType = "指纹钥匙"
		break
	case "03":
		keyType = "IC卡钥匙"
		break
	}

	var hash map[string]interface{}
	if devKv != nil {
		_ = json.Unmarshal([]byte(devKv.Value), &hash)
	}

	for _, token := range tokens {

		if hash["name"] == nil {
			err = weixinOperator.TemplateMsg.SendOpenDoorMsg(token.UserId, "用户 "+lockUserId, "Lock", keyType)
		} else {
			nickName := hash["name"].(string)
			err = weixinOperator.TemplateMsg.SendOpenDoorMsg(token.UserId, nickName, "Lock", keyType)
		}
	}
	return err
}

func (self devBiz) addUserLog(conn *t11Model.DbConn, msg *MqttMsg, data []byte) t11Errors.T11Error {

	userJwt, err := models.UserDeviceDao.GetTokensByDeviceId(conn, msg.DevId)
	if err != nil {
		return err
	}

	userType := msg.Data[12:14]
	lockUserId, err := t11Util.HexStringToDecimal(msg.Data[8:12])
	if err != nil {
		return err
	}

	for _, jwt := range userJwt {
		err = weixinOperator.TemplateMsg.SendUserRegistermsg(jwt.UserId, lockUserId, userType)
	}
	return err
}

func (self devBiz) deleteUserLog(conn *t11Model.DbConn, msg *MqttMsg, data []byte) t11Errors.T11Error {

	userJwt, err := models.UserDeviceDao.GetTokensByDeviceId(conn, msg.DevId)
	if err != nil {
		return err
	}

	userType := msg.Data[12:14]
	lockUserId, err := t11Util.HexStringToDecimal(msg.Data[8:12])
	if err != nil {
		return err
	}

	for _, jwt := range userJwt {
		err = weixinOperator.TemplateMsg.SendUserDeleteMsg(jwt.UserId, lockUserId, userType)
	}
	return err
}

func (self devBiz) modifyPasswordLog(conn *t11Model.DbConn, msg *MqttMsg, data []byte) t11Errors.T11Error {

	tokens, err := models.UserDeviceDao.GetTokensByDeviceId(conn, msg.DevId)
	if err != nil {
		return err
	}

	_lockUserId := msg.Data[8:12]
	lockUserId, err := t11Util.HexStringToDecimal(_lockUserId)
	if err != nil {
		return err
	}

	devKv, err := models.DeviceKvDao.GetByKey(conn, _lockUserId)
	if err != nil {
		return err
	}

	for _, token := range tokens {

		var hash map[string]interface{}
		json.Unmarshal([]byte(devKv.Value), &hash)

		if devKv == nil || hash["name"] == nil {
			err = weixinOperator.TemplateMsg.SendModifyPasswdMsg(token.UserId, "用户 "+lockUserId)
		} else {
			nickName := hash["name"].(string)
			err = weixinOperator.TemplateMsg.SendModifyPasswdMsg(token.UserId, nickName)
		}
	}
	return err
}

func (self devBiz) warningLog(conn *t11Model.DbConn, msg *MqttMsg, data []byte) t11Errors.T11Error {

	tokens, err := models.UserDeviceDao.GetTokensByDeviceId(conn, msg.DevId)
	if err != nil {
		return err
	}

	warningCode := data[2]
	warningMsg := ""

	switch warningCode {
	case 0x04:
		warningMsg = "门锁正在被撬"
		break
	case 0x06:
		warningMsg = "门锁电量低"
		break
	case 0x08:
		warningMsg = "非法的钥匙开门"
		break
	default:
		break
	}

	if warningMsg != "" {
		for _, token := range tokens {
			err = weixinOperator.TemplateMsg.SendAlarmMsg(token.UserId, warningMsg, "chan")
		}
	}
	return err
}

func (self devBiz) restoreLockLog(conn *t11Model.DbConn, msg *MqttMsg, data []byte) t11Errors.T11Error {

	tokens, err := models.UserDeviceDao.GetTokensByDeviceId(conn, msg.DevId)
	if err != nil {
		return err
	}

	for _, token := range tokens {
		err = weixinOperator.TemplateMsg.SendAlarmMsg(token.UserId, "门锁已恢复出厂设置", "chan")
	}
	return err
}

func (self devBiz) UploadLog(conn *t11Model.DbConn, msg *MqttMsg, data []byte) t11Errors.T11Error {
	// 插入一条日志到数据库
	err := models.DeviceLogDao.Create(conn, msg.DevId, t11Util.BytesToHexStringWithoutSpace(data))
	if err != nil {
		t11Log.Debuglnf("插入失败 ...")
	}

	cmd := data[1]

	switch cmd {
	case 0x01:
		t11Log.Debuglnf("添加用户")
		err = self.addUserLog(conn, msg, data)
		break
	case 0x02:
		t11Log.Debuglnf("删除用户")
		err = self.deleteUserLog(conn, msg, data)
		break
	case 0x03:
		t11Log.Debuglnf("修改密码")
		err = self.modifyPasswordLog(conn, msg, data)
		break
	case 0x04:
		t11Log.Debuglnf("用户开门")
		err = self.upLoadOpenLog(conn, msg, data)
		break
	case 0x05:
		t11Log.Debuglnf("报警信息")
		err = self.warningLog(conn, msg, data)
		break
	case 0x06:
		t11Log.Debuglnf("门锁重置")
		err = self.restoreLockLog(conn, msg, data)
		break
	}

	self.notifyWs(conn, msg)
	return err
}

//将mqtt消息转发给微信用户
func (self *devBiz) notifyWs(conn *t11Model.DbConn, msg *MqttMsg) {
	wxUsers, err := self.GetWxUsersByDev(conn, msg.DevId)
	if err != nil {
		return
	}
	for _, i := range wxUsers {
		_ = WsMsgSender.SendMsg(i, msg)
	}
}

func (self *devBiz) GetWxUsersByDev(conn *t11Model.DbConn, devId string) ([]*models.JwtToken, t11Errors.T11Error) {
	dev, err := models.DeviceDao.GetById(conn, devId)
	if err != nil {
		return nil, nil
	}
	return models.UserDeviceDao.GetTokensByDeviceId(conn, dev.Id)
}

func (self *devBiz) CmdFromDev(conn *t11Model.DbConn, msg *MqttMsg, _data []byte) t11Errors.T11Error {
	self.notifyWs(conn, msg)
	return nil
}

func (self devBiz) ListLogs(conn *t11Model.DbConn, devs []*models.Device) ([]*models.DeviceLog, t11Errors.T11Error) {
	if len(devs) == 0 {
		return nil, nil
	}
	var devIds []string
	for _, item := range devs {
		devIds = append(devIds, item.Id)
	}

	return models.DeviceLogDao.GetByDevIds(conn, devIds)
}

func (self devBiz) ListDeviceKvs(conn *t11Model.DbConn, devs []*models.Device) ([]*models.DeviceKv, t11Errors.T11Error) {
	if len(devs) == 0 {
		return nil, nil
	}
	var devIds []string
	for _, item := range devs {
		devIds = append(devIds, item.Id)
	}
	return models.DeviceKvDao.GetByDevIds(conn, devIds)
}

func (self *devBiz) GetUserDeviceKvs(conn *t11Model.DbConn, token *models.JwtToken) ([]*models.UserDeviceKv, t11Errors.T11Error) {
	return models.UserKvDao.GetDeviceKvByUser(conn, token)
}

func (self *devBiz) GetUserDevice(conn *t11Model.DbConn, token *models.JwtToken) (*models.UserDevice, t11Errors.T11Error) {
	return models.UserDeviceDao.GetUserDeviceByUser(conn, token)
}

func (self *devBiz) GetDeviceType(conn *t11Model.DbConn, token *models.JwtToken) ([]map[string]string, t11Errors.T11Error) {

	var userDevs []*models.UserDevice
	_, e := conn.QueryTable(&models.UserDevice{}).Filter("UserId", token.ToId()).All(&userDevs)
	if e != nil {
		return nil, t11Errors.Wrap(e)
	}

	var ret []map[string]string
	for _, user := range userDevs {
		var dev = make(map[string]string)
		dev["devId"] = user.DevId
		dev["type"] = user.BindType
		ret = append(ret, dev)
	}

	return ret, t11Errors.Wrap(e)
}
